// Copyright (C) 2016 All rights reserved.
// Author: liufeng11@letv.com (Liu Feng)
// Description:
#include "FontFeatureExtractor.h"
#include <stdexcept>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include <cmath>

void FontFeatureExtractor::Show(const unsigned char* ch, int rows, int cols) {
  if (!ch) return;
  for (int i = 0; i < rows; ++i) {
    for (int j = 0; j < cols; ++j) {
      printf("%s", ch[i*rows+j] == 1? "**" : "  ");
    }
    printf("\n");
  }
  
}
bool FontFeatureExtractor::GetFeature(unsigned int charCode, std::vector<double>* feature) {
  feature->clear();
  unsigned char data[ROWS*COLS] = { 0 };
  if (!GetData(charCode, data)) return false;
  ExtractFeature(data, feature);
  return true;
}

std::vector<double> FontFeatureExtractor::operator()(unsigned int charCode) {
  std::vector<double> feature;
  if (!GetFeature(charCode, &feature)) {
    throw std::invalid_argument("Empty character!"); 
  }
  return feature;
}

void FontFeatureExtractor::ExtractFeature(const unsigned char* data, std::vector<double>* feature) {
  // simple strategy
  if (!feature) return;
  std::vector<double> &v = *feature;
  v.resize(2*ROWS*COLS, 0);
 
  unsigned char t[COLS*ROWS] = { 0 };  
  Transpose(data, t, ROWS, COLS);

  for (int i = 0; i < ROWS*COLS; ++i) {
    v[i] = data[i];
  }

  for (int i = ROWS*COLS; i < 2*ROWS*COLS; ++i) {
    v[i] = t[i-ROWS*COLS];
  }

  Normalize(&v);
}

void FontFeatureExtractor::Transpose(const unsigned char* ch, unsigned char* r, int rows, int cols) {
  if (!r) return;
  for (int i = 0; i < cols; ++i) {
    for (int j = 0; j < rows; ++j) {
      r[i*cols+j] = ch[j*rows+i];
    }
  }
}

void FontFeatureExtractor::Normalize(std::vector<double> *v) {
  if (!v) return;

  const double lambda = 1e-4;
  
  double sum = 0;

  for (size_t i = 0; i < v->size(); ++i) {
    sum += (*v)[i]*(*v)[i];
  }

  sum = sqrt(sum);

  for (size_t i = 0; i < v->size(); ++i) {
    (*v)[i] = (*v)[i] / (lambda + sum);
  }
}

bool FontFeatureExtractor::GetData(unsigned int charCode, unsigned char* data) {
  if (!data) return false;
  FT_Library pFTLib = NULL;
  FT_Face pFTFace = NULL;
  FT_Error error = 0;
  error = FT_Init_FreeType(&pFTLib);
  if (error) {
    pFTLib = 0;
    printf(" There is some error when Init Library ");
    exit(-1);
  }

  error = FT_New_Face(pFTLib, "../fonts/font.ttf", 0, &pFTFace);

  bool ret = true;
  if (!error) {
    FT_Set_Pixel_Sizes(pFTFace, SETROWS, SETCOLS);
    FT_Glyph glyph;

    // load glyph for the character
    FT_Load_Glyph(pFTFace, FT_Get_Char_Index(pFTFace, charCode), FT_LOAD_DEFAULT);
    error = FT_Get_Glyph(pFTFace -> glyph, &glyph);
    if (!error) {
      // convert glyph to bitmap with 256 gray
      FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
      FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph) glyph;
      FT_Bitmap *bitmap = &bitmap_glyph -> bitmap;

      if (bitmap->rows == 0 || bitmap->width == 0) {
        ret = false;
      }
      else {
        int i, j;

        for (i = 0; i < bitmap->rows; ++i) {
          for (j = 0; j < bitmap->width; ++j) {
            data[i * COLS + j] = bitmap->buffer[i * bitmap->width + j];
          }
        }
      }


      // free glyph
      FT_Done_Glyph(glyph);
      glyph = NULL;
    }

    // free face
    FT_Done_Face(pFTFace);
    pFTFace = NULL;

  } else {
    printf("Loading the ttf file failed!\n");
    printf("error code is %d\n", error);
    exit(-1);
  }

  // free FreeType Lib
  FT_Done_FreeType(pFTLib);
  pFTLib = NULL;
  return ret;
}
